﻿@inject NavigationManager _navigationManager
@inject IAssistantService _assistantService
@inject IStorageService _storageService
@inject IModelCatalogService _modelCatalogService
@inject ChatState _chatState
@inject ISnackbar Snackbar

@implements IDisposable

<EditForm Model="@Assistant" OnValidSubmit="OnValidSubmit">
    <DataAnnotationsValidator />
    <div class="d-flex flex-column flex-grow-1 gap-3 pa-4">
        <MudText>Name</MudText>
        <MudTextField @bind-Value="Assistant!.Name" Variant="Variant.Outlined" Margin="Margin.Dense" For="@(() => Assistant!.Name)" />

        <MudText>Description</MudText>
        <MudTextField @bind-Value="Assistant!.Description" Variant="Variant.Outlined" Margin="Margin.Dense" For="@(() => Assistant!.Description)" />

        <MudText>Avatar</MudText>
        <AvatarUpload ImageUrl="@Assistant.AvatarUrl" OnInputFileChanged="OnInputFileChanged" />
        
        <MudText>Model</MudText>
        <MudSelect @bind-Value="Assistant.DefaultModel" Margin="Margin.Dense" T="string" Variant="Variant.Outlined" For="@(() => Assistant!.DefaultModel)">
            @foreach (var model in ModelCatalog.Models)
            {
                <MudSelectItem Value="@model.Name" />
            }
        </MudSelect>

        <MudText>Metaprompt</MudText>
        <MudTextField @bind-Value="Assistant!.Metaprompt" 
                      T="string" Variant="Variant.Outlined" 
                      AutoGrow 
                      Lines="7" 
                      MaxLines="10" 
                      Margin="Margin.Dense" 
                      For="@(() => Assistant!.Metaprompt)" />

        <div class="px-2">
            <MudText Typo="Typo.caption" Class="mt-0" Style="color: var(--mud-palette-text-secondary); font-size: .75rem; text-align: start; font-weight: 400; line-height: 1.66; letter-spacing: .03333em;">
                @((MarkupString)assistantBehaviorGuidelines)
            </MudText>
        </div>
    </div>
    <div class="d-flex flex-row flex-grow-1 justify-end gap-4 pa-4">
        <MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary" Class="ml-auto">Save</MudButton>
    </div>
</EditForm>

@code 
{
    [Parameter] public Guid AssistantId { get; set; }
    [Parameter] public EventCallback OnAssistantSubmit { get; set; }
    private AssistantResponse Assistant { get; set; } = new();
    private ModelCatalogResponse ModelCatalog { get; set; } = new();

    private const string assistantBehaviorGuidelines = @"
Enter the Metaprompt here. This set of instructions will define your assistant's behavior
in every conversation, guiding how it interacts and responds. Keep it concise, clear, and
reflective of the assistant's intended personality and capabilities.<br /><br />
<strong>Available placeholders:</strong><br />
- <span style='color: var(--mud-palette-primary);'><strong>{DATE}</strong></span> will be replaced with local current date";

    private const string DefaultAvatarUrl = "https://raw.githubusercontent.com/ktutak1337/Stellar-Chat/main/docs/assets/images/_ed19c10c-bbad-4514-8df4-eef37400e218.jpg";

    private bool success;

    protected override async Task OnInitializedAsync()
    {
        _chatState.SelectedAssistantChanged += StateHasChanged;

        await LoadModels();
    }

    protected async override Task OnParametersSetAsync()
    {
        await PopulateForm();
    }

    private async void OnValidSubmit(EditContext context)
    {
        if (AssistantId != Guid.Empty)
        {
            await UpdateAssistantAsync(Assistant!);
        }
        else
        {
            await CreateAssistantAsync();
        }

        success = true;
        await OnAssistantSubmit.InvokeAsync();
        StateHasChanged();
    }

    private async Task PopulateForm()
    {
        if (Guid.Empty != AssistantId)
        {
            await FetchAssistantToUpdate();
        }
        else
        {
            SetupNewAssistantParameters();
        }
    }

    private async Task LoadModels()
    {
        var response = await _modelCatalogService.BrowseModelsCatalog();
        var modelCatalog = response.Value;

        if (!response.Succeeded)
        {
            ShowSnackbar("Failed to load model catalog. Please try again.", Severity.Error);
        }

        if (modelCatalog is not null)
        {
            ModelCatalog = modelCatalog;
        }
    }

    private async Task FetchAssistantToUpdate()
    {
        var response = await _assistantService.GetAssistant(AssistantId);
        var assistant = response.Value;

        if (assistant is not null)
        {
            Assistant = new AssistantResponse
            {
                Id = assistant.Id,
                Name = assistant.Name,
                Metaprompt = assistant.Metaprompt,
                Description = assistant.Description,
                AvatarUrl = assistant.AvatarUrl ?? DefaultAvatarUrl,
                DefaultModel = assistant.DefaultModel,
                DefaultVoice = assistant.DefaultVoice,
                IsDefault = assistant.IsDefault,
                CreatedAt = assistant.CreatedAt,
                UpdatedAt = assistant.UpdatedAt
            };
        }
    }

    private void SetupNewAssistantParameters()
    {
        Assistant!.AvatarUrl = DefaultAvatarUrl;
        Assistant.IsDefault = false;
    }

    private async Task CreateAssistantAsync()
    {
        if (Assistant is not null)
        {
            var response = await _assistantService.CreateAssistant(Assistant);

            if (!response.Succeeded)
            {
                ShowSnackbar("Failed to create assistant {assistant.Name}. Please try again.", Severity.Error);
            }

            _chatState.SetSelectedAssistant(Assistant);
            ShowSnackbar($"Assistant {Assistant.Name} was created successfully!", Severity.Success);
        }
    }

    private async Task UpdateAssistantAsync(AssistantResponse assistant)
    {
        if (assistant is not null)
        {
            var response = await _assistantService.UpdateAssistant(assistant);

            if (!response.Succeeded)
            {
                ShowSnackbar("Failed to update assistant {assistant.Name}. Please try again.", Severity.Error);
            }

            _chatState.SetAssignedAssistant(assistant);
            _chatState.SetSelectedAssistant(assistant);
            _chatState.NotifyAssistantUpdated();
            success = true;

            ShowSnackbar($"Assistant {assistant.Name} was updated successfully!", Severity.Success);
        }
    }

    private async Task OnInputFileChanged(InputFileChangeEventArgs e)
    {
        var file = e.File;

        if (file is not null)
        {
            var response = await _storageService.UploadFileAsync(file, "avatar");
            Assistant.AvatarUrl = response.Url;
        }
    }

    private void ShowSnackbar(string message, Severity severity)
    {
        Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopRight;

        Snackbar.Add(message, severity, options =>
        {
            options.HideTransitionDuration = 100;
        });
    }

    public void Dispose()
    {
        _chatState.SelectedAssistantChanged -= StateHasChanged;
    }
}
